package cn.nexd.collector.beacon;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.text.TextUtils;

import java.util.List;

import cn.nexd.collector.NexdCollector;
import cn.nexd.collector.NexdCollectorConfiguration;
import cn.nexd.collector.bean.BeaconScannerResult;
import cn.nexd.collector.bean.BeaconScannerResultStory;
import cn.nexd.collector.listener.BeaconCollectorListener;
import cn.nexd.collector.thread.ThreadPoolManager;

/**
 * Created by codngfish on 16/5/16.
 */
public class BeaconCollectorTask extends Beacon {

    private BluetoothManager bluetoothManager;
    private BluetoothAdapter bluetoothAdapter;
    private DefaultBeaconScanCallback beaconScanCallback;

    private BeaconScannerResultStory beaconScannerResultStory = null;

    public BeaconCollectorTask(Context context, NexdCollectorConfiguration collectorConfiguration, BeaconCollectorListener beaconCollectorListener) {
        super(context, collectorConfiguration, beaconCollectorListener);
    }

    @Override
    public boolean initilazeCollector() {

        collectorRunning = false;
        stop = true;

        if (!permssion()) {
            ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerCollectorEventThreadPool(new HandlerCollectorInterruptThread(NexdCollector.CollectorState.COLLECTOR_INTERRUPT_TYPE_PERMISSION_UNAVAILABLE));
            return false;
        }
        bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);

        if (bluetoothManager == null) {
            ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerCollectorEventThreadPool(new HandlerCollectorInterruptThread(NexdCollector.CollectorState.COLLECTOR_INTERRUPT_TYPE_COLLECTOR_UNAVAILABLE));
            return false;
        }


        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
            bluetoothAdapter = bluetoothManager.getAdapter();
        } else {
            ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerCollectorEventThreadPool(new HandlerCollectorInterruptThread(NexdCollector.CollectorState.COLLECTOR_INTERRUPT_TYPE_COLLECTOR_UNAVAILABLE));
            return false;
        }


        if (bluetoothAdapter == null) {
            ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerCollectorEventThreadPool(new HandlerCollectorInterruptThread(NexdCollector.CollectorState.COLLECTOR_INTERRUPT_TYPE_COLLECTOR_UNAVAILABLE));
            return false;
        }

        if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF || bluetoothAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF || bluetoothAdapter.getScanMode() == BluetoothAdapter.SCAN_MODE_NONE) {
            ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerCollectorEventThreadPool(new HandlerCollectorInterruptThread(NexdCollector.CollectorState.COLLECTOR_INTERRUPT_TYPE_COLLECTOR_STATE_UNAVAILABLE));
            return false;
        }

        beaconScanCallback = new DefaultBeaconScanCallback();
        beaconScannerResultStory = new BeaconScannerResultStory();
        return true;
    }

    @Override
    public boolean startCollector() {

        stop = false;
        if (!bluetoothAdapter.startLeScan(beaconScanCallback)) {
            ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerCollectorEventThreadPool(new HandlerCollectorInterruptThread(NexdCollector.CollectorState.COLLECTOR_INTERRUPT_TYPE_COLLECTOR_UNAVAILABLE));
            return false;
        }
        ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerCollectorEventThreadPool(new HandlerCollectorStartThread());

        ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerBeaconCollectorLifecycleThreadPool(new HandlerListenerThread(), collectorConfiguration.beacon_collector_delay, collectorConfiguration.bluetoothCollectorRate);

        collectorRunning = true;

        return true;
    }

    @Override
    public boolean stopCollector() {
        bluetoothAdapter.stopLeScan(beaconScanCallback);
        collectorRunning = false;
        stop = true;
        return true;
    }

    @Override
    public boolean destroyCollector() {
        stop = true;
        if (bluetoothAdapter != null) {
            bluetoothAdapter = null;
        }


        if (bluetoothAdapter != null) {
            bluetoothAdapter = null;
        }

        collectorRunning = false;

        //        ThreadPoolManager.getThreadPoolManagerInstance().shutdownBeaconCollectorLifecycleThreadPool();
        return true;
    }

    private class DefaultBeaconScanCallback implements BluetoothAdapter.LeScanCallback {
        @Override
        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
            if (TextUtils.equals(device.getAddress(), "00:00:00:00:00:00")) {
                ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerCollectorEventThreadPool(new HandlerCollectorInterruptThread(NexdCollector.CollectorState.COLLECTOR_INTERRUPT_TYPE_CAN_NOT_ACCESS_DATA));
                //                ThreadPoolManager.getThreadPoolManagerInstance().shutdownBeaconCollectorLifecycleThreadPool();
            } else {
                ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerCollectorEventThreadPool(new HandlerCollectorDataThread(device, rssi, scanRecord, System.currentTimeMillis()));
            }
        }
    }

    private class HandlerCollectorInterruptThread implements Runnable {
        private NexdCollector.CollectorState collectorState;

        public HandlerCollectorInterruptThread(NexdCollector.CollectorState collectorState) {
            this.collectorState = collectorState;
        }

        @Override
        public void run() {
            collectorListener.onCollectorInterrupt(collectorState);
        }
    }

    private class HandlerCollectorDataThread implements Runnable {

        private BluetoothDevice device;
        private int rssi;
        private byte[] scanRecord;
        private long timestamp;

        public HandlerCollectorDataThread(BluetoothDevice device, int rssi, byte[] scanRecord, long timestamp) {
            this.device = device;
            this.rssi = rssi;
            this.scanRecord = scanRecord;
            this.timestamp = timestamp;
        }

        @Override
        public void run() {
            if (stop) {
                return;
            }
            beaconScannerResultStory.addBeaconScannerResult(device, rssi, scanRecord, timestamp);
        }
    }

    private boolean stop = false;
    private int counter = 0;

    private class HandlerCollectorStartThread implements Runnable {
        @Override
        public void run() {
            collectorListener.onCollectionStart();
        }
    }

    private class HandlerListenerThread implements Runnable {
        @Override
        public void run() {

            if (stop) {
                return;
            }
            List<BeaconScannerResult> beaconScannerResults = beaconScannerResultStory.getBeaconScannerResults();
            if (beaconScannerResults != null) {
                if (beaconScannerResults.size() > 4) {
                    collectorListener.onCollectionSuccess(beaconScannerResults);
                    counter = 0;
                } else {
                    if (counter == 5) {
                        collectorListener.onCollectorFailed(NexdCollector.CollectorState.COLLECTOR_FAILED_TYPE_NO_BEACON_FOUND);
                        counter = 0;
                    }

                    counter = counter + 1;
                }
            }
            if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF || bluetoothAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF || bluetoothAdapter.getScanMode() == BluetoothAdapter.SCAN_MODE_NONE) {
                ThreadPoolManager.getThreadPoolManagerInstance().addTaskToHandlerCollectorEventThreadPool(new HandlerCollectorInterruptThread(NexdCollector.CollectorState.COLLECTOR_INTERRUPT_TYPE_COLLECTOR_STATE_UNAVAILABLE));
                //                ThreadPoolManager.getThreadPoolManagerInstance().shutdownBeaconCollectorLifecycleThreadPool();
                stopCollector();
            }
        }
    }
}
